#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/errno.h>

char *name = "second_dev";
static struct class *second_dev_class;

volatile unsigned long *gpncon;
volatile unsigned long *gpndat;

static int second_dev_open(struct inode *inode, struct file *file)
{
	*gpncon = *gpncon & ~0xff;
	
	return 0;	
}

static ssize_t second_dev_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
{
	unsigned char key_vals[4];
	int regval;

	if (size != sizeof(key_vals)) {
		return -EINVAL;
	}	
	
	regval = *gpndat;
	
	key_vals[0] = (regval & (1 << 0)) ? 1 : 0;
	key_vals[1] = (regval & (1 << 1)) ? 1 : 0;
	key_vals[2] = (regval & (1 << 2)) ? 1 : 0;
	key_vals[3] = (regval & (1 << 3)) ? 1 : 0;
	
	if (copy_to_user(buf, key_vals, sizeof(key_vals))) {
		return -EINVAL;		
	}

	return sizeof(key_vals);
}

struct file_operations second_dev_fops = {
	.owner = THIS_MODULE,
	.open = second_dev_open,
	.read = second_dev_read,0
};

int major;

static int __init second_dev_init(void) 
{
	major = register_chrdev(0, name, &second_dev_fops);

	second_dev_class = class_create(THIS_MODULE, name);
	device_create(second_dev_class, NULL, MKDEV(major, 0), &second_dev_init, "%s", name);	
	
	printk("%s_init and the device is %d\n", name, major);

	gpncon = (volatile unsigned long *)ioremap(0x7F008830, 16);
	gpndat = gpncon + 1;

	return 0;
}

static void __exit second_dev_exit(void)
{
	unregister_chrdev(major, name);
	
	device_destroy(second_dev_class, MKDEV(major, 0));
	class_destroy(second_dev_class);
	
	printk("%s_exit and device is %d\n", name, major);
	
	iounmap(gpncon);
}

MODULE_LICENSE("GPL");
module_init(second_dev_init);
module_exit(second_dev_exit);
